package net.cl.util.ui;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.LayoutManager;

import net.cl.util.ui.SlidingPanel.Position;


/**
 * Special LayoutManager exclusively designed for the SlidingPanel class.
 *
 * @author David
 */
class SlidingLayout implements LayoutManager
{
	private int		mMinWidth			= 0;
	private int		mMinHeight			= 0;
	private int		mPreferredWidth		= 0;
	private int		mPreferredHeight	= 0;
	private boolean	mSizeUnknown		= true;

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void addLayoutComponent(String arg0, Component arg1)
	{
		// - Not needed -
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void removeLayoutComponent(Component arg0)
	{
		// - Not needed -
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Dimension minimumLayoutSize(Container pParent)
	{
		updateSize(pParent);

		Insets insets = pParent.getInsets();
		int width = this.mMinWidth + insets.left + insets.right;
		int height = this.mMinHeight+ insets.top + insets.bottom;

		return new Dimension(width, height);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Dimension preferredLayoutSize(Container pParent)
	{
		updateSize(pParent);

		Insets insets = pParent.getInsets();
		int width = this.mPreferredWidth + insets.left + insets.right;
		int height = this.mPreferredHeight+ insets.top + insets.bottom;

		return new Dimension(width, height);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void layoutContainer(Container pParent)
	{
		if(this.mSizeUnknown)
		{
			this.updateSize(pParent);
		}

		SlidingPanel parent = this.ensureContainerType(pParent);
		Insets insets = pParent.getInsets();
		Component mainComponent = parent.getMainComponent();

		// Stop any possible animation in the parent component
		parent.cancelAnimation();
		int mainYPos = insets.top;

		Position visibleMenuPosition = parent.getActiveBorderComponent();
		if(visibleMenuPosition != null)
		{
			// Main component must be shifted in some direction.
			Component visibleMenu = parent.getBorderComponent(visibleMenuPosition);
			mainYPos += visibleMenuPosition.shiftMainComponent(visibleMenu.getPreferredSize().height);
		}

		// Set this position of the main component
		mainComponent.setBounds(
				insets.left,
				mainYPos,
				parent.getWidth() - (insets.left + insets.right),
				parent.getHeight() - (insets.top + insets.bottom));


		// Set the position for all border components
		for(Position pos : Position.values())
		{
			if(parent.hasBorderComponentAt(pos))
			{
				Component cur = parent.getBorderComponent(pos);

				int height = cur.getPreferredSize().height;
				cur.setBounds(
						insets.left,
						insets.top + pos.computeYPosition(height,
								parent.getHeight() - insets.bottom),
						parent.getWidth() - (insets.left + insets.right),
						height);
			}
		}
	}

	/**
	 * Updates the preferred and minimum size of the layout.
	 *
	 * @param pParent The parent component. Must be of type SlidingPanel.
	 * @throws IllegalArgumentException if pCont is not of type SlidingPanel
	 */
	private void updateSize(Container pParent)
	{
		// Get required objects
		SlidingPanel parent = ensureContainerType(pParent);
		Component mainComponent = parent.getMainComponent();
		Dimension mainPrefSize = mainComponent.getPreferredSize();
		Dimension mainMinSize = mainComponent.getMinimumSize();

		// Recalculate preferred/minimum width and height.
		mPreferredWidth = mainPrefSize.width;
		mPreferredHeight = mainPrefSize.height;
		mMinWidth = mainMinSize.width;
		mMinHeight = mainMinSize.height;

		this.mSizeUnknown = false;
	}

	/**
	 * Checks the type of the argument. If argument is not a SlidingPanel, an exception is thrown.
	 *
	 * @param pCont The container to check
	 * @return pCont, but casted to SlidingPanel
	 * @throws IllegalArgumentException if pCont is not of type SlidingPanel
	 */
	private SlidingPanel ensureContainerType(Container pCont)
	{
		if(pCont instanceof SlidingPanel)
		{
			return (SlidingPanel) pCont;
		}
		else
		{
			throw new IllegalArgumentException("SlidingLayout must operate on a SlidingPanel!");
		}
	}

	@Override
	public String toString()
	{
		return getClass().getSimpleName();
	}
}